home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / c / cserial.zip / 8250DTR.C < prev    next >
C/C++ Source or Header  |  1990-04-04  |  12KB  |  456 lines

  1. /*
  2.  *                                DTR8250.C
  3.  *
  4.  *                    NSC8250 DTR Handshake ISR Module
  5.  *
  6.  *                           Written for the
  7.  *
  8.  *                              Datalight
  9.  *                           Microsoft V 5.x
  10.  *                                TurboC
  11.  *                                  &
  12.  *                               Zortech
  13.  *
  14.  *                             C Compilers
  15.  *
  16.  *            Copyright (c) John Birchfield 1987, 1988, 1989
  17.  */
  18.  
  19. #include <stdio.h>
  20. #include "dependnt.h"
  21. #include "queue.h"
  22. #include "8250nsc.h"
  23. #include "8250dtr.h"
  24. #include "timer.h"
  25.  
  26. #if (!defined (TRUE))
  27. #    define TRUE  (1)
  28. #    define FALSE (0)
  29. #endif
  30.  
  31. unsigned DTR_PORT_channel;      /* Either 1 or 2 for COM1 or COM2       */
  32. char    dtr8250_SAVE_int_mask,  /* saved interrupt controller mask word */
  33.         dtr8250_IER_save = 0,   /* Saved off Interrupt Enable Register  */
  34.         dtr8250_LCR_save = 0,   /* Saved off Line Control Register      */
  35.         dtr8250_MCR_save = 0,   /* Saved off Modem Control Register     */
  36.         dtr8250_DL_lsb = 0,     /* Saved off Baud Rate LSB              */
  37.         dtr8250_DL_msb = 0;     /* Saved off Baud Rate MSB              */
  38.  
  39.  
  40.  
  41. volatile unsigned DTR_PORT_addr;
  42. volatile char DTR_PORT_status, RCV_disabled = FALSE, XMIT_disabled = TRUE, dtr8250_MSR_reg = 0;
  43. volatile QUEUE *dtr8250_inqueue;
  44. #if (defined (DLC))
  45. extern void outp ();
  46. #endif
  47.  
  48.  
  49. #define DISABLE_xmit outbyte (DTR_PORT_addr+IER, RX_enable)
  50. #define ENABLE_xmit  outbyte (DTR_PORT_addr+IER, RX_TX_enable)
  51. #define DROPPED_cts  ((dtr8250_MSR_reg&0x10)==0)
  52. #define DROPPED_dsr  ((dtr8250_MSR_reg&0x20)==0)
  53. #define DROPPED_dtr  ((dtr8250_MSR_reg&0x30)!=0x30)
  54. #define ASSERT_dtr   outbyte (inbyte (DTR_PORT_addr+MCR)|9, DTR_PORT_addr+MCR)
  55. #define DROP_dtr     outbyte (inbyte (DTR_PORT_addr+MCR)&0x0A, DTR_PORT_addr+MCR)
  56. #define ASSERT_rts   outbyte (inbyte (DTR_PORT_addr+MCR)|0x0A, DTR_PORT_addr+MCR)
  57. #define DROP_rts     outbyte (inbyte (DTR_PORT_addr+MCR)&9, DTR_PORT_addr+MCR)
  58. #define TSRE_bit     0x40
  59.  
  60.  
  61.  
  62. /*
  63.  *    DTR8250_ISR - This Interrupt Service Routine attached to either COM1
  64.  *                  or COM2.  It drives the NSC8250 with Hardware
  65.  *                  Handshaking.  i.e. Flow of Control is maintained by 
  66.  *                  RTS (Request to Send) CTS (Clear to Send) Logic.
  67.  *                After installation by Catch_Rt, it catches the
  68.  *                8250 interrupts and en_queues incoming characters
  69.  *                from the Serial Port - and de-queues outgoing
  70.  *                characters to the Serial Port.
  71.  */
  72.  
  73. #if (!defined (DLC))
  74. void    (interrupt far * dtr_save_vec) (void);
  75. void interrupt far 
  76. dtr8250_isr (void)
  77. #else
  78. int 
  79. dtr8250_isr ()
  80. #endif
  81. {
  82.     int     ch;
  83.     char    test_status;
  84.  
  85.     enable ();
  86.     test_status = inbyte ((DTR_PORT_addr + IIR));
  87.     do
  88.     {
  89.         switch (test_status)
  90.         {
  91.  
  92.             case IIR_rls:
  93.                 DTR_PORT_status |= inbyte ((DTR_PORT_addr + LSR));
  94.                 break;
  95.  
  96.             case IIR_receive:
  97.                 ch = inbyte (DTR_PORT_addr);
  98.                 if ((en_queue (dtr8250_inqueue, ch) < 10) && !RCV_disabled)
  99.                 {
  100.                     RCV_disabled = TRUE;
  101.                     DROP_dtr;
  102.                 }
  103.                 else
  104.                 if (RCV_disabled && (queue_avail (dtr8250_inqueue) > 20))
  105.                 {
  106.                     RCV_disabled = FALSE;
  107.                     ASSERT_dtr;
  108.                 }
  109.                 break;
  110.  
  111.             case IIR_transmit:
  112.                 DISABLE_xmit;
  113.                 break;
  114.  
  115.             case IIR_mstatus:
  116.                 dtr8250_MSR_reg = inbyte (DTR_PORT_addr + MSR);
  117.                 if (RCV_disabled && (queue_avail (dtr8250_inqueue) > 20))
  118.                 {
  119.                     RCV_disabled = FALSE;
  120.                     ASSERT_dtr;
  121.                 }
  122.                 break;
  123.         }
  124.     } while ((test_status = inbyte (DTR_PORT_addr + IIR)) != IIR_complete);
  125.     disable ();
  126.     outbyte (INT_cntrl, EOI_word);
  127. #if (defined (DLC))
  128.     return (1);
  129. #endif
  130. }
  131.  
  132.  
  133.  
  134.  
  135. /*
  136.  *    DTR8250_INIT - Here we get the address of the 8250 Port
  137.  *                   which corresponds to the channel passed in.
  138.  *                   We then massage the 8259 Interrupt Controller
  139.  *                   calculate the Physical Interrupt and save off
  140.  *                   the 8250's current contents.  Then attach the
  141.  *                   nsc8250_interrupt routine to the interrupt and
  142.  *                   return the rt returned index for saving - it's
  143.  *                   needed to terminate the interrupt.
  144.  */
  145.  
  146. #define DTR8250_STACK_SIZE 1024
  147. int        dtr8250_intno;
  148. static int dtr_intmask [] = { 0xef, 0xf7, 0xef, 0xf7 };
  149. /*
  150.  * The above 8259 mask bits are determined from the formula
  151.  *          mask = ~(1 << (5 - PORT_CHANNEL));
  152.  * The array assumes that COM3 and COM4 use the same interrupts
  153.  * as COM1 and COM2.
  154.  */
  155. static int dtr_intno   [] = { 12, 11, 12, 11 };
  156. /*
  157.  * The above interrupt number array is based on the algorithm
  158.  *       dtr8250_intno = (13 - PORT_channel);
  159.  */
  160.  
  161.  
  162. void 
  163. dtr8250_init (channel, buf_size)
  164. int     channel, buf_size;
  165. {
  166.     int     Dos_address, mask;
  167.     DTR_PORT_channel = channel;
  168.     dtr8250_inqueue = alloc_queue (buf_size);
  169.     Dos_address = (DTR_PORT_channel - 1) * 2;
  170.     peekmem (0x40, Dos_address, DTR_PORT_addr);
  171.     mask = dtr_intmask [DTR_PORT_channel-1];
  172.     dtr8250_SAVE_int_mask = inbyte (INT_mask);
  173.     mask &= dtr8250_SAVE_int_mask;
  174.     dtr8250_intno = dtr_intno [DTR_PORT_channel-1];
  175.     dtr8250_LCR_save = inbyte (DTR_PORT_addr + LCR);
  176.     disable ();
  177.     outbyte (DTR_PORT_addr + LCR, dtr8250_LCR_save | LCR_DLAB);
  178.     dtr8250_MCR_save = inbyte (DTR_PORT_addr + MCR);
  179.     dtr8250_DL_lsb = inbyte (DTR_PORT_addr);
  180.     dtr8250_DL_msb = inbyte (DTR_PORT_addr + 1);
  181.     outbyte (DTR_PORT_addr + LCR, dtr8250_LCR_save & 0x7F);
  182.     dtr8250_IER_save = inbyte (DTR_PORT_addr + IER);
  183.     enable ();
  184. #if (defined (DLC))
  185.     int_intercept (dtr8250_intno, &dtr8250_isr, DTR8250_STACK_SIZE);
  186. #else
  187.     dtr_save_vec = getvect (dtr8250_intno);
  188.     setvect (dtr8250_intno, dtr8250_isr);
  189. #endif
  190.     DELAY_init ();
  191.     outbyte (INT_mask, mask);
  192. }
  193.  
  194.  
  195.  
  196.  
  197. /*
  198.  *    DTR8250_TERM - This routine restores the RS232 Vector back to its
  199.  *                   state before DTR8250_INIT was called.
  200.  */
  201.  
  202. void 
  203. dtr8250_term (int restore)
  204. {
  205.     disable ();
  206.     outbyte (INT_mask, dtr8250_SAVE_int_mask);
  207.     if (restore)
  208.     {
  209.         outbyte (DTR_PORT_addr + LCR, LCR_DLAB);
  210.         outbyte (DTR_PORT_addr, dtr8250_DL_lsb);
  211.         outbyte (DTR_PORT_addr + 1, dtr8250_DL_msb);
  212.         outbyte (DTR_PORT_addr + MCR, dtr8250_MCR_save);
  213.         outbyte (DTR_PORT_addr + LCR, 0x7F);
  214.         outbyte (DTR_PORT_addr + IER, dtr8250_IER_save);
  215.         outbyte (DTR_PORT_addr + LCR, dtr8250_LCR_save);
  216.     }
  217. #if (defined (DLC))
  218.     int_restore (dtr8250_intno);
  219. #else
  220.     setvect (dtr8250_intno, dtr_save_vec);
  221. #endif
  222. }
  223.  
  224.  
  225.  
  226.  
  227. /*
  228.  *    DTR8250_READ - this routine looks in the RS232hw_inqueue for a character
  229.  *
  230.  */
  231.  
  232. int 
  233. dtr8250_read (void)
  234. {
  235.     int     ch;
  236.     disable ();
  237.     ch = de_queue (dtr8250_inqueue);
  238.     enable ();
  239.     return (ch);
  240. }
  241.  
  242.  
  243.  
  244.  
  245. /*
  246.  *    DTR8250_TIMED_READ - attempts to read rs232 port - if no char
  247.  *                         available in number of seconds passed
  248.  *                         returns -1
  249.  */
  250.  
  251. int 
  252. dtr8250_timed_read (int sec)
  253. {
  254.     int     ch;
  255.  
  256.     timer_set ();
  257.     while ((ch = dtr8250_read ()) == -1)
  258.         if ((timer_read () / 18) > sec)
  259.             break;
  260.     return (ch);
  261. }
  262.  
  263.  
  264.  
  265.  
  266. /*
  267.  *    DTR8250_WRITE - plain vanilla write to the port - check to see that
  268.  *                    the chip may need a kick in the pants before returning
  269.  */
  270.  
  271. int 
  272. dtr8250_write (char ch)
  273. {
  274.     while ((inbyte (DTR_PORT_addr + LSR) & TSRE_bit) == 0)
  275.         ;
  276.     dtr8250_MSR_reg = inbyte ((DTR_PORT_addr + MSR));
  277.     if (DROPPED_dtr)
  278.         return -1;
  279.     outbyte (DTR_PORT_addr, ch);
  280.     if (RCV_disabled && (queue_avail (dtr8250_inqueue) > 20))
  281.     {
  282.         RCV_disabled = FALSE;
  283.         ASSERT